package org.little.aop.framework;

import org.little.aop.Advice;
import org.little.aop.Pointcut;
import org.little.util.Assert;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Tinyspot
 * @date 2022-05-29 21:27
 */
public class AopConfigSupport implements AopConfig {

    private boolean proxyTargetClass = false;
    private List<Class> interfaces = new ArrayList<>();
    Object targetObject = null;
    List<Advice> advices = new ArrayList<>();

    public AopConfigSupport() {
    }

    @Override
    public Object getTargetObject() {
        return this.targetObject;
    }

    @Override
    public void setTargetObject(Object targetObject) {
        this.targetObject = targetObject;
    }

    @Override
    public Class<?> getTargetClass() {
        return this.targetObject.getClass();
    }

    public void addInterface(Class<?> interf) {
        Assert.notNull(interf, "Interface must not be null");
        if (!interf.isInterface()) {
            throw new IllegalArgumentException("[" + interf.getName() + "] is not an interface");
        }
        if (!this.interfaces.contains(interf)) {
            this.interfaces.add(interf);
        }
    }

    @Override
    public Class<?>[] getProxiedInterfaces() {
        return this.interfaces.toArray(new Class[this.interfaces.size()]);
    }

    @Override
    public boolean isInterfaceProxied(Class<?> interf) {
        for (Class proxyInterf : this.interfaces) {
            if (interf.isAssignableFrom(proxyInterf)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void addAdvice(Advice advice) {
        this.advices.add(advice);
    }

    @Override
    public boolean isProxyTargetClass() {
        return proxyTargetClass;
    }

    public void setProxyTargetClass(boolean proxyTargetClass) {
        this.proxyTargetClass = proxyTargetClass;
    }

    @Override
    public List<Advice> getAdvices() {
        return this.advices;
    }

    @Override
    public List<Advice> getAdvices(Method method) {
        List<Advice> result = new ArrayList<>();
        for (Advice advice : this.getAdvices()) {
            Pointcut pointcut = advice.getPointcut();
            if (pointcut.getMethodMatcher().matches(method)) {
                result.add(advice);
            }
        }
        return result;
    }
}
